from abc import ABC, abstractmethod
from typing import List, Tuple, Optional

# 棋子基类
class Piece(ABC):
    def __init__(self, color: str, position: Tuple[int, int]):
        """
        初始化棋子
        :param color: 棋子颜色 ('white' 或 'black')
        :param position: 棋子位置，格式为 (行, 列)，从0开始
        """
        self.color = color  # 棋子颜色
        self.position = position  # 棋子位置
        self.has_moved = False  # 标记棋子是否已经移动过（用于特殊规则，如王车易位）
        self.symbol = ""  # 棋子符号，子类中定义
    
    @abstractmethod
    def get_possible_moves(self, board) -> List[Tuple[int, int]]:
        """
        获取棋子的所有可能移动位置
        :param board: 棋盘对象
        :return: 可能的移动位置列表
        """
        pass
    
    def is_valid_position(self, position: Tuple[int, int]) -> bool:
        """
        检查位置是否在棋盘范围内
        :param position: 要检查的位置
        :return: 如果位置有效返回True，否则返回False
        """
        row, col = position
        return 0 <= row < 8 and 0 <= col < 8
    
    def move(self, new_position: Tuple[int, int]):
        """
        移动棋子到新位置
        :param new_position: 新位置
        """
        self.position = new_position
        self.has_moved = True


# 王（国王）
class King(Piece):
    def __init__(self, color: str, position: Tuple[int, int]):
        super().__init__(color, position)
        self.symbol = 'K' if color == 'white' else 'k'
    
    def get_possible_moves(self, board) -> List[Tuple[int, int]]:
        """
        获取国王可能的移动位置
        国王可以向任意方向移动一格
        """
        possible_moves = []
        row, col = self.position
        
        # 国王可以移动的8个方向
        directions = [
            (-1, -1), (-1, 0), (-1, 1),
            (0, -1),           (0, 1),
            (1, -1),  (1, 0),  (1, 1)
        ]
        
        for dr, dc in directions:
            new_row, new_col = row + dr, col + dc
            new_position = (new_row, new_col)
            
            if not self.is_valid_position(new_position):
                continue
                
            # 检查目标位置是否为空或者是否有敌方棋子
            piece_at_target = board.get_piece_at(new_position)
            if piece_at_target is None or piece_at_target.color != self.color:
                # 需要检查移动后是否会被将军
                # 这部分逻辑在游戏类中实现
                possible_moves.append(new_position)
        
        # 王车易位的逻辑会在游戏类中实现
        
        return possible_moves


# 后（皇后）
class Queen(Piece):
    def __init__(self, color: str, position: Tuple[int, int]):
        super().__init__(color, position)
        self.symbol = 'Q' if color == 'white' else 'q'
    
    def get_possible_moves(self, board) -> List[Tuple[int, int]]:
        """
        获取皇后可能的移动位置
        皇后可以沿着直线和对角线移动任意格数
        """
        possible_moves = []
        row, col = self.position
        
        # 皇后可以移动的8个方向（横、竖、斜）
        directions = [
            (-1, -1), (-1, 0), (-1, 1),
            (0, -1),           (0, 1),
            (1, -1),  (1, 0),  (1, 1)
        ]
        
        for dr, dc in directions:
            for i in range(1, 8):  # 最多移动7格
                new_row, new_col = row + i * dr, col + i * dc
                new_position = (new_row, new_col)
                
                if not self.is_valid_position(new_position):
                    break
                
                piece_at_target = board.get_piece_at(new_position)
                if piece_at_target is None:
                    possible_moves.append(new_position)
                elif piece_at_target.color != self.color:
                    possible_moves.append(new_position)
                    break  # 不能越过敌方棋子
                else:
                    break  # 不能越过己方棋子
        
        return possible_moves


# 车
class Rook(Piece):
    def __init__(self, color: str, position: Tuple[int, int]):
        super().__init__(color, position)
        self.symbol = 'R' if color == 'white' else 'r'
    
    def get_possible_moves(self, board) -> List[Tuple[int, int]]:
        """
        获取车可能的移动位置
        车可以沿着横向和纵向移动任意格数
        """
        possible_moves = []
        row, col = self.position
        
        # 车可以移动的4个方向（横、竖）
        directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]
        
        for dr, dc in directions:
            for i in range(1, 8):  # 最多移动7格
                new_row, new_col = row + i * dr, col + i * dc
                new_position = (new_row, new_col)
                
                if not self.is_valid_position(new_position):
                    break
                
                piece_at_target = board.get_piece_at(new_position)
                if piece_at_target is None:
                    possible_moves.append(new_position)
                elif piece_at_target.color != self.color:
                    possible_moves.append(new_position)
                    break  # 不能越过敌方棋子
                else:
                    break  # 不能越过己方棋子
        
        return possible_moves


# 象
class Bishop(Piece):
    def __init__(self, color: str, position: Tuple[int, int]):
        super().__init__(color, position)
        self.symbol = 'B' if color == 'white' else 'b'
    
    def get_possible_moves(self, board) -> List[Tuple[int, int]]:
        """
        获取象可能的移动位置
        象可以沿着对角线移动任意格数
        """
        possible_moves = []
        row, col = self.position
        
        # 象可以移动的4个方向（对角线）
        directions = [(-1, -1), (-1, 1), (1, -1), (1, 1)]
        
        for dr, dc in directions:
            for i in range(1, 8):  # 最多移动7格
                new_row, new_col = row + i * dr, col + i * dc
                new_position = (new_row, new_col)
                
                if not self.is_valid_position(new_position):
                    break
                
                piece_at_target = board.get_piece_at(new_position)
                if piece_at_target is None:
                    possible_moves.append(new_position)
                elif piece_at_target.color != self.color:
                    possible_moves.append(new_position)
                    break  # 不能越过敌方棋子
                else:
                    break  # 不能越过己方棋子
        
        return possible_moves


# 马（骑士）
class Knight(Piece):
    def __init__(self, color: str, position: Tuple[int, int]):
        super().__init__(color, position)
        self.symbol = 'N' if color == 'white' else 'n'
    
    def get_possible_moves(self, board) -> List[Tuple[int, int]]:
        """
        获取马可能的移动位置
        马走"日"字，可以越过其他棋子
        """
        possible_moves = []
        row, col = self.position
        
        # 马可以移动的8个位置
        knight_moves = [
            (-2, -1), (-2, 1), (-1, -2), (-1, 2),
            (1, -2), (1, 2), (2, -1), (2, 1)
        ]
        
        for dr, dc in knight_moves:
            new_row, new_col = row + dr, col + dc
            new_position = (new_row, new_col)
            
            if not self.is_valid_position(new_position):
                continue
            
            piece_at_target = board.get_piece_at(new_position)
            if piece_at_target is None or piece_at_target.color != self.color:
                possible_moves.append(new_position)
        
        return possible_moves


# 兵（卒）
class Pawn(Piece):
    def __init__(self, color: str, position: Tuple[int, int]):
        super().__init__(color, position)
        self.symbol = 'P' if color == 'white' else 'p'
        # 记录是否可以被吃过路兵
        self.en_passant_vulnerable = False
    
    def get_possible_moves(self, board) -> List[Tuple[int, int]]:
        """
        获取兵可能的移动位置
        兵只能向前移动，首次可以移动两格，可以斜向吃子
        """
        possible_moves = []
        row, col = self.position
        
        # 根据棋子颜色确定移动方向
        direction = -1 if self.color == 'white' else 1
        
        # 前进一格
        new_row = row + direction
        if 0 <= new_row < 8 and board.get_piece_at((new_row, col)) is None:
            possible_moves.append((new_row, col))
            
            # 如果是首次移动，可以前进两格
            if not self.has_moved:
                new_row = row + 2 * direction
                if 0 <= new_row < 8 and board.get_piece_at((new_row, col)) is None:
                    possible_moves.append((new_row, col))
        
        # 斜向吃子（左斜）
        new_row, new_col = row + direction, col - 1
        if 0 <= new_row < 8 and 0 <= new_col < 8:
            piece_at_target = board.get_piece_at((new_row, new_col))
            if piece_at_target is not None and piece_at_target.color != self.color:
                possible_moves.append((new_row, new_col))
            
            # 吃过路兵
            elif piece_at_target is None:
                piece_beside = board.get_piece_at((row, new_col))
                if (piece_beside is not None and 
                    piece_beside.color != self.color and 
                    isinstance(piece_beside, Pawn) and 
                    getattr(piece_beside, 'en_passant_vulnerable', False)):
                    possible_moves.append((new_row, new_col))
        
        # 斜向吃子（右斜）
        new_row, new_col = row + direction, col + 1
        if 0 <= new_row < 8 and 0 <= new_col < 8:
            piece_at_target = board.get_piece_at((new_row, new_col))
            if piece_at_target is not None and piece_at_target.color != self.color:
                possible_moves.append((new_row, new_col))
            
            # 吃过路兵
            elif piece_at_target is None:
                piece_beside = board.get_piece_at((row, new_col))
                if (piece_beside is not None and 
                    piece_beside.color != self.color and 
                    isinstance(piece_beside, Pawn) and 
                    getattr(piece_beside, 'en_passant_vulnerable', False)):
                    possible_moves.append((new_row, new_col))
        
        return possible_moves 